#ifndef __scheduler_H__
#define __scheduler_H__

#include <memory>
#include <vector>
#include <list>
#include <iostream>
#include "fiber.h"
#include "thread.h"

namespace framework
{


//协程调度器
//内部有一个线程池，支持协程在线程池里面切换
//线程池中有多个线程，线程中有多个协程
class Scheduler
{
public:
    using ptr = std::shared_ptr<Scheduler>;
    using MutexType = Mutex;

    //线程池默认线程数量
    //是否使用当前调用线程
    //协程调度器名称
    Scheduler(size_t threads = 1, bool use_calle = true, const std::string& name = "");

    virtual ~Scheduler();

    //返回协程调度器名称
    const std::string getName() const { return m_name; }

    //启动协程调度器
    void start();

    //停止协程调度器
    void stop();


//=================== static ======================
    //返回当前协程调度器
    static Scheduler* GetThis();

    //返回当前协程调度器的调度协程
    static Fiber* GetMainFiber();
//=================== static ======================


    //调度协程
    //fc: 协程或者函数
    //thread：协程执行的线程id，-1表示任意线程
    template<class FiberorCb>
    void schedule(FiberorCb fc, int thread = -1)
    {
        bool need_tickle = false;
        {
            MutexType::Lock lock(m_mutex);
            need_tickle = scheduleNoLock(fc, thread);
        }

        if(need_tickle)
        {
            tickle();
        }
    }


    //批量调度协程
    //协程数组的起始迭代器和结束迭代器
    template<class InputIterator>
    void schedule(InputIterator begin, InputIterator end)
    {
        bool need_tickle = false;
        {
            MutexType::Lock lock(m_mutex);
            while (begin != end)
            {
                //这里使用了&，会调用swap函数
                need_tickle = scheduleNoLock(&*begin,-1) || need_tickle;
                ++begin;         
            }
            
        }

        if(need_tickle)
        {
            tickle();
        }
    }
protected:
    //通知协程调度器有任务了
    virtual void tickle();
    
    //返回是否可以停止
    virtual bool stopping();

    //协程无任务时可调度执行idle协程
    virtual void idle();

    //协程调度函数
    void run();

    //设置当前的协程调度器
    void setThis();

    //是否有空闲线程
    bool hasIdleThreads() { return m_idleThreadCount > 0; }

private:
    //协程调度启动（无锁）
    template<class FiberOrcb> //协程或者是回调函数
    bool scheduleNoLock(FiberOrcb fc, int thread)
    {
        bool need_tickle = m_fibers.empty();
        FiberAndThread ft(fc, thread);
        if(ft.fiber || ft.cb)
        {
            m_fibers.push_back(ft);
        }
        return need_tickle;
    }

private:
    
    // 协程/函数/线程组
    struct FiberAndThread
    {
        Fiber::ptr fiber;           //协程
        std::function<void()> cb;   //协程执行函数
        int thread;                 //线程id

        FiberAndThread():thread(-1) {}

        FiberAndThread(Fiber::ptr f, int thr):fiber(f),thread(thr) {}
        FiberAndThread(Fiber::ptr* f, int thr):thread(thr)
        {
            fiber.swap(*f);
        }

        FiberAndThread(std::function<void()> f, int thr):cb(f),thread(thr) {}
        FiberAndThread(std::function<void()>* f, int thr):thread(thr)
        {
            cb.swap(*f);
        }

        //重置数据
        void reset()
        {
            fiber = nullptr;
            cb = nullptr;
            thread = -1;
        }
    };

private:
    MutexType m_mutex; //互斥量
    std::vector<Thread::ptr> m_threads; //线程池
    std::list<FiberAndThread> m_fibers; //待执行的协程队列
    Fiber::ptr m_rootFiber; //当use_caller为true时有效，调度协程（调度器的主协程）
    std::string m_name; //协程调度器名称

protected:
    std::vector<int> m_threadIds; //协程下的线程id数组
    size_t m_threadCount = 0;     //线程数量
    std::atomic<size_t> m_activeThreadCount = {0};  //工作线程数量
    std::atomic<size_t> m_idleThreadCount = {0};    //空闲线程数量
    bool m_stopping = true;       //当前是否停止
    bool m_autoStop = false;      //是否自动停止
    int m_rootThread = 0;         //主线程id(use_caller)
};


}




#endif
